package com.bestvike.stone.spring.rabbit.core;

import com.bestvike.stone.core.lang.Convert;
import com.bestvike.stone.spring.context.ThreadContext;
import com.bestvike.stone.spring.context.TraceContext;
import com.bestvike.stone.spring.rabbit.RabbitRetryMessage;
import com.bestvike.stone.spring.rabbit.RabbitUtils;
import com.bestvike.stone.spring.rabbit.exception.ConsumeDisabledException;
import com.bestvike.stone.spring.trace.rabbit.IncomingLog;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;

/**
 * Created by 许崇雷 on 2018-09-04.
 */
public interface IHandlerAdapter {
    //1.外部调用使用此方法,此方法中应该调用 invokeCore(...) 方法
    Object invoke(Message<?> message, Object... providedArgs);

    //3.真正执行用户代码
    Object invokeSuper(Message<?> message, Object... providedArgs) throws Exception;

    //2.该方法进行日志输出等操作,真正执行时调用 invokeSuper(...) 方法
    default Object invokeCore(String action, Message<?> message, Object... providedArgs) {
        ThreadContext.init(null);
        TraceContext.init();
        IncomingLog.writeBeginLog(action, message);
        long begin = System.currentTimeMillis();
        try {
            Object result = this.invokeSuper(message, providedArgs);
            IncomingLog.writeEndLog(action, message, System.currentTimeMillis() - begin);
            return result;
        } catch (ConsumeDisabledException e) {
            IncomingLog.writeDisabledLog(action, message, System.currentTimeMillis() - begin);
            throw e;
        } catch (Exception e) {
            //重试
            MessageHeaders headers = message.getHeaders();
            int retry = Convert.defaultInteger(headers.get(RabbitRetryMessage.DELIVERY_ATTEMPT));
            if (retry < RabbitRetryMessage.MAX_DELIVERY_ATTEMPT) {
                retry++;
                IncomingLog.writeWarnLog(action, message, retry, e, System.currentTimeMillis() - begin);
                String queue = (String) headers.get(AmqpHeaders.CONSUMER_QUEUE);
                RabbitRetryMessage retryMessage = new RabbitRetryMessage(message, retry);
                RabbitUtils.retry(queue, retryMessage);
                return null;
            }
            //超过最大重试次数
            IncomingLog.writeErrorLog(action, message, e, System.currentTimeMillis() - begin);
            return null;
        } finally {
            TraceContext.reset();
            ThreadContext.reset();
        }
    }
}
